# -*- coding: koi8-r -*-
## OJAB talker module
## Copyright (C) Alexey Frolov <falexey@nm.ru>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.

import string,random,gzip

lpo=None

def ttows(t,a):
    ws=[]
    w=t[0]
    for n in t[1:]:
	if n in a or w in a:
	    ws.append(w)
	    w=''
	w+=n
    ws.append(w)
    return ws

def addpo(lofs,cpos,cpo,po,c):
    nb=len(po)
    for n in xrange(c):
	cpos.append([])
	cpo.append([])
	po.append([])
	for o in xrange(lofs):
	    cpos[nb].append(0)
	    cpo[nb].append([])
	    po[nb].append([])
	nb+=1

def adddb(lofs,cpos,cpo,po,pot):
    cpot=len(pot)
    for np in xrange(cpot-1):
	lo=cpot-np-1
	if lo>lofs: lo=lofs
	nw=pot[np]
	for o in xrange(lo):
	    ofs=o+1
	    if pot[np+ofs] in po[nw][o]:
		n=po[nw][o].index(pot[np+ofs])
		cpo[nw][o][n]+=1
		while n>0 and cpo[nw][o][n]>cpo[nw][o][n-1]:
		    a=cpo[nw][o][n]
		    cpo[nw][o][n]=cpo[nw][o][n-1]
		    cpo[nw][o][n-1]=a
		    a=po[nw][o][n]
		    po[nw][o][n]=po[nw][o][n-1]
		    po[nw][o][n-1]=a
		    n-=1
	    else:
		if cpos[nw][o]<=lpo:
		    po[nw][o].append(pot[np+ofs])
		    cpo[nw][o].append(1)
		    cpos[nw][o]+=1
		else:
		    po[nw][o][lpo-1]=pot[np+ofs]
		    cpo[nw][o][lpo-1]=0

def spai(ws,lofs,cpos,cpo,po,nws):
    to,gcpo,gpo,scpo,spo=[],[],[],[],[]
    for o in xrange(lofs):
	gpo.append([])
	gcpo.append([])
	scpo.append([])
	spo.append([])
    for nw in nws:
	if cpos[nw]==0: nw=int(random.random()*len(ws)-0.25)
	while nw>=0 and cpos[nw]>0 and ((len(to)<4 and random.random()>0.25*float(len(to))) or random.random()>0.5):
	    gcpo=gcpo[1:]+[cpo[nw][lofs-1]]
	    gpo=gpo[1:]+[po[nw][lofs-1]]
	    scpo=scpo[1:]+[cpo[nw][lofs-1]]
	    spo=spo[1:]+[po[nw][lofs-1]]
	    for o in xrange(lofs-1):
		gncpo,gnpo=[],[]
		for n in xrange(cpos[nw][o]):
		    if po[nw][o][n] in gpo[o]:
			ipo=gpo[o].index(po[nw][o][n])
			gnpo.append(gpo[o][ipo])
			gncpo.append(gcpo[o][ipo]+cpo[nw][o][n])
		    if po[nw][o][n] in spo[o]: scpo[o][spo[o].index(po[nw][o][n])]+=cpo[nw][o][n]
		    else:
			spo[o].append(po[nw][o][n])
			scpo[o].append(cpo[nw][o][n])
		gcpo[o],gpo[o]=gncpo,gnpo
	    if len(gpo[0])==0:
		gpo[0]=spo[0]
		gcpo[0]=scpo[0]
	    l=len(gpo[0])
	    if l>4: l=4
	    while len(gpo[0])>l:
		n=min(gcpo[0])
		gpo[0].remove(gpo[0][gcpo[0].index(n)])
		gcpo[0].remove(n)
	    if gpo[0]!=[]:
		rpo=[]
		for n in xrange(len(gpo[0])):
		    for i in xrange(gcpo[0][n]): rpo.append(gpo[0][n])
		nw=rpo[int(random.random()*(len(rpo)-0.25))]
	    else: nw=int(random.random()*len(ws)-0.25)
	    if to==[] or not to[-1:][0] in ('.',',') or not ws[nw] in ('.',','): to.append(ws[nw])
    if to[0] in ('.',','): to=to[1:]
    if to[-1:]==[',']: to=to[:-1]
    return ','.join(string.split('.'.join(string.split(' '.join(to),' .')),' ,'))

def sp(ws,lofs,cpos,cpo,po,text,boadddb):
    if text=='': text=' '
    ta=ttows(string.lower(text),(' ','.',',','-',':',';','?','"',"'",'[',']','{','}','=','<','>','/','\\','!','@','#','$','%','^','&','*','(',')','_','+','|'))
    nws=[]
    for t in ta:
	if t in ws: nws.append(ws.index(t))
	else:
	    if boadddb and t!=' ':
		ws.append(t)
		addpo(lofs,cpos,cpo,po,1)
		nws.append(len(ws)-1)
    if nws==[]: nws=[int(random.random()*len(ws)-0.25)]
    to=spai(ws,lofs,cpos,cpo,po,nws)
    if boadddb: adddb(lofs,cpos,cpo,po,nws)
    return to

def dbopen(dbn,dbnpo):
    ws=gzip.open(dbn).read().decode('utf-8').split(chr(0))
    if ws==['']: ws=[]
    cws=len(ws)
    a=gzip.open(dbnpo).read()
    lofs=ord(a[0])+ord(a[1])*256
    r=2
    cpos=[]
    cpo=[]
    po=[]
    for n in xrange(cws):
	cpos.append([])
	cpo.append([])
	po.append([])
	for o in xrange(lofs):
	    cpos[n].append(ord(a[r])+ord(a[r+1])*256)
	    r+=2
	    cpo[n].append([])
	    po[n].append([])
    	    for i in xrange(cpos[n][o]):
		cpo[n][o].append(ord(a[r])+ord(a[r+1])*256)
    		po[n][o].append(ord(a[r+2])+ord(a[r+3])*256)
		r+=4
    return ws,lofs,cpos,cpo,po
